package contegor.scire.core.queries;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import contegor.scire.core.Concept;
import contegor.scire.core.Connectable;
import contegor.scire.core.Container;
import contegor.scire.core.Id;
import contegor.scire.core.IdFragment;
import contegor.scire.core.InfiniteSingletonList;
import contegor.scire.core.NeedsPrecedent;
import contegor.scire.core.ReturnPoint;
import contegor.scire.core.ReturnPointDecoratorForErrorsHandling;
import contegor.scire.core.Task;
import contegor.scire.core.TaskId;
import contegor.scire.core.WithSubsequentsExtensible;

/**
 * {@link GetConcepts} {@link Query} extensible with subsequent {@link Task}s.
 *
 * @version $Revision$
 * @author  Héctor Cirbián Pousa ($Author$)
 */
public class GetConceptsExtensible<O extends Connectable> extends GetConcepts implements WithSubsequentsExtensible<Concept, O> {
  private static final long serialVersionUID = 3095513534634426155L;

  private List<Concept> results;
  private List<NeedsPrecedent<? super Concept, O>> subsequents;

  public GetConceptsExtensible(Id targetContainerId, IdFragment... ids) {
    super(targetContainerId, ids);
    this.results = new LinkedList<Concept>();
  }

  @Override
  public void process(Container targetContainer) {
    for (IdFragment id: ids) {
      Concept c = targetContainer.getConcept(id);
      if ((c != null) && c.isVisibleTo(this.taskId.getTransactionId())) {
        this.returnPoint.manage(this.taskId, c);
        results.add(c);
      }
    }
  }

  @Override
  public GetConceptsExtensible<O> withIt(NeedsPrecedent<? super Concept, O> subsequent) {
    if (this.subsequents == null)
      this.subsequents = new LinkedList<NeedsPrecedent<? super Concept,O>>();
    this.subsequents.add(subsequent);
    return this;
  }

  @Override
  public List<? extends Collection<Concept>> getResultsForSubsequentTasks() {
    if ((this.subsequents == null) || (this.subsequents.size() == 0))
      return Collections.emptyList();
    return new InfiniteSingletonList<List<Concept>>(this.results, this.subsequents.size());
  }

  @Override
  public List<? extends NeedsPrecedent<? super Concept, O>> getSubsequentTasks() {
    if (this.subsequents == null)
      return Collections.emptyList();
    return this.subsequents;
  }

  @Override
  public List<? extends ReturnPoint<? super O>> getSubsequentTasksReturnPoints() {
    if ((this.subsequents == null) || (this.subsequents.size() == 0))
      return Collections.emptyList();
    return new InfiniteSingletonList<ReturnPoint<? super O>>(new ReturnPointDecoratorForErrorsHandling<O>(this.returnPoint), this.subsequents.size());
  }

  @Override
  public void setTaskId(TaskId taskId) {
    super.setTaskId(taskId);
    if (this.subsequents != null)
      for (NeedsPrecedent<?,?> subsequent: this.subsequents)
        subsequent.setTaskId(taskId.next(true));
  }
}
